package com.beerandjesus.sportofkings.handicapper.strategy.brisnet.singlefile;

import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;

import org.apache.commons.lang.StringUtils;

import com.beerandjesus.sportofkings.handicapper.model.*;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.*;
import com.beerandjesus.sportofkings.handicapper.factory.profile.ProfileFactory;

public class NonMaidenRaceAnalysisStrategyImpl extends
		AbstractRaceAnalysisStrategy implements
		NonMaidenRaceAnalysisStrategy<HorseRace> {
	
	private static final int MAX_RACES_FOR_WPS_CONSIDERATION = 5;

	private static final int MAX_RACES_FOR_SPEED_CONSIDERATION = 6;

	private static final int MAX_RACES_FOR_UP_CLOSE_CONSIDERATION = 8;

    private static final BigDecimal TWO_AND_THREE_QUARTERS = new BigDecimal("2.75");
	private static final BigDecimal THREE_AND_A_HALF = new BigDecimal("3.5");

    private ProfileFactory profileFactory;

    public RaceAnalysisResultVO analyze(HorseRace race) {
		Race r = race.getRace();
		List<Horse> horses = race.getHorses();
		RaceAnalysisResultVOImpl vo = new RaceAnalysisResultVOImpl();
		setCommonFields(vo, r, horses);
        List<HorseAnalysisResult> results = new ArrayList<HorseAnalysisResult>();
        for (Horse h : horses) {
            NonMaidenHorseAnalysisResultImpl result = new NonMaidenHorseAnalysisResultImpl();
            Integer pp = new Integer(h.getPostPosition());
            result.setPostPosition(pp);
            Integer qPts;
            try {
                qPts = new Integer(h.getQuirinSpeedPoints());
            } catch (NumberFormatException e) {
                qPts = -1;
            }
            ResultType type;
			if (qPts < 0) {
				type = ResultType.UNKNOWN;
			} else if (qPts < 4) {
				type = ResultType.SLOW_EARLY_SPEED;
			} else {
				type = ResultType.FAST_EARLY_SPEED;
			}
            result.setResultType(type);
            // name
            result.setName(h.getName());
			// Quirin style speed points
            result.setQuirinSpeedPoints(qPts.toString());
			switch (type) {
			case SLOW_EARLY_SPEED:
				// Up close 2 times within last 8 races
				// up close =
				// 2 3/4 lengths at 2nd call for sprints
				// 3 1/2 lengths at 2nd call for routes
				int upCloseCount = 0;
				int raceCount = 0;
				for (PastPerformance perf : h.getPastPerformances()) {
					raceCount++;
					if (raceCount > MAX_RACES_FOR_UP_CLOSE_CONSIDERATION) {
						break;
					}
					String lenOrMarg = perf.getCall2ndLenOrMargin();
					if (!StringUtils.isEmpty(lenOrMarg)) {
						BigDecimal lom = new BigDecimal(lenOrMarg);
						BigDecimal comp;
						if (calc.isRoute(perf.getDistance())) {
							comp = THREE_AND_A_HALF;
						} else {
							comp = TWO_AND_THREE_QUARTERS;
						}
						if (lom.compareTo(comp) <= 0) {
							upCloseCount++;
						}
					}
				}
				Boolean upClose = false;
				if (upCloseCount > 1) {
					upClose = true;
				}
                result.setUpCloseWhenStalking(upClose);
				break;
            case FAST_EARLY_SPEED:
                // Note if runner can win off pace.
                // Any occurrence in past performances passes.
                Boolean winsOffPace = false;
                for (PastPerformance perf : h.getPastPerformances()) {
                    if (equal(perf.getFinishPosition(), 1) && greaterThan(perf.getCallPositionSecond(), 1)) {
                        winsOffPace = true;
                        break;
                    }
                }
                result.setWinsOffPace(winsOffPace);

                break;
			}
			// Speed & wps
			Integer par = getInteger(r.getBrisSpeedPar(), 0);
			int raceCount = 0;
			int maxSpeed = 0;
			int parCount = 0;
			int[] wps = new int[3];
			for (PastPerformance perf : h.getPastPerformances()) {
				raceCount++;
				if (raceCount <= MAX_RACES_FOR_SPEED_CONSIDERATION) {
					Integer speed = getInteger(perf.getBrisSpeedRating(), 0);
					if (speed > maxSpeed) {
						maxSpeed = speed;
					}
					if (speed >= par) {
						parCount++;
					}
				}
				if (raceCount <= MAX_RACES_FOR_WPS_CONSIDERATION) {
					Integer pos = getInteger(perf.getFinishPosition(), 99);
					if (pos == 1) {
						wps[0]++;
					} else if (pos == 2) {
						wps[1]++;
					} else if (pos == 3) {
						wps[2]++;
					}
				}

			}
            result.setParSpeedCount(parCount);
            result.setSpeedFigure("" + maxSpeed);
            result.setRecentWins(wps[0]);
            result.setRecentPlaces(wps[1]);
            result.setRecentShows(wps[2]);
			// Workouts
            List<String> works = new ArrayList<String>();
            for (Workout w : h.getWorkouts()) {
                if (workResolver.isSharpWorkout(w)) {
                    works.add(calc.distanceFromYardsShortNotation(w.getDistance()));
                }
            }
            result.setFastWorkouts(works);
            MixedNumeral mlOdds = null;
            if (!StringUtils.isEmpty(h.getMorningLineOdds())) {
                mlOdds = calc.toFraction(new BigDecimal(h.getMorningLineOdds()));
            }
            result.setMorningLine(mlOdds);
            // Profiles
            List<AnalysisProfile> profs = getProfileFactory().getProfiles(race, h);
            result.setProfiles(profs);
            results.add(result);
        }

		vo.setResults(results);
		return vo;
	}

    public ProfileFactory getProfileFactory() {
        return profileFactory;
    }

    public void setProfileFactory(ProfileFactory profileFactory) {
        this.profileFactory = profileFactory;
    }

}
